/**************************************************************************//**
 * @item     CosyOS Config
 * @file     mcucfg_cmx.h
 * @brief    CMSIS Cortex-M Core Config File
 * @author   迟凯峰
 * @version  V2.0.0
 * @date     2023.03.07
 ******************************************************************************/

#ifndef __MCUCFG_CMX_H
#define __MCUCFG_CMX_H

/******************************************************************************
 *                             USER Definitions                               *
 ******************************************************************************/

          //*** <<< Use Configuration Wizard in Context Menu >>> ***//

///////////////////////////////////////////////////////////////////////////////
// <s> 标准头文件
// <i> 定义与您的MCU相匹配的标准头文件，您的c文件中不必再包含此文件。
// <i> 示例一：stm32f10x.h
// <i> 示例二：stm32f4xx.h
#define MCUCFG_STANDARDHEAD             "stm32f10x.h"
///////////////////////////////////////////////////////////////////////////////
// <o> 系统时钟
// <i> 告知操作系统您所配置的系统时钟，单位为MHZ。
#define MCUCFG_SYSCLK                   72
#if !MCUCFG_SYSCLK
#error 非法的设置值！
#endif
///////////////////////////////////////////////////////////////////////////////
// <o> 系统滴答时钟源
// <0=> 外部时钟 <1=> 内核时钟
// <i> 在此配置系统滴答时钟源，您无需再额外配置。
// <i> 如果您使用了外部晶振且时钟为整数，可配置系统滴答时钟源为外部时钟，以提高滴答定时器的精度。
#define MCUCFG_STKCLKSOURCE             1
///////////////////////////////////////////////////////////////////////////////
// <o> 系统启动任务的任务栈大小
// <i> 最小值：
// <i> 不使用浮点寄存器：64；
// <i> 使用浮点寄存器：200。
#define __STACKSIZE_STARTER__           1024
#if __STACKSIZE_STARTER__ < __BASICSTACKSIZE__
#error 非法的设置值！
#endif

// <o> 系统空闲任务的任务栈大小
// <i> 最小值：
// <i> 不使用浮点寄存器：64；
// <i> 使用浮点寄存器：200。
#define __STACKSIZE_SYSIDLE__           64
#if __STACKSIZE_SYSIDLE__ < __BASICSTACKSIZE__
#error 非法的设置值！
#endif
///////////////////////////////////////////////////////////////////////////////
// <o> 中断服务栈深度
// <i> 此项参数取决于您在中断中调用异步服务的总次数及中断的频率。
// <i> 可开启中断服务栈监控，监控历史上的最大值，再适当增大，以确保其不会溢出。
#define MCUCFG_ISSDEPTH                 128
#if MCUCFG_ISSDEPTH < 2
#error 非法的设置值！
#endif
///////////////////////////////////////////////////////////////////////////////
// <q> 中断服务栈监控
// <i> 是否开启中断服务栈监控？
// <i> 开启后，系统将自动监控中断服务栈的深度，并通过任务管理器输出。输出格式为：历史最大值/设置值。
// <i> 建议仅在调试阶段开启此项功能，正式的产品应禁用。
#define MCUCFG_SVSTACKMONITOR           1
///////////////////////////////////////////////////////////////////////////////
// <q> 任务栈监控
// <i> 是否开启任务栈监控？
// <i> 开启后，系统将自动插入任务栈监控代码至每一个任务和系统服务的开始处。
// <i> 而后，您应尽可能的把任务栈监控代码插入到每一个被任务调用的自定义函数内，并作为函数的第一句代码。
// <i> 然而，即便如此也无法实现100%可靠的任务栈监控，因为必然会有一部分函数无法插入任务栈监控代码，如标准库函数。
// <i> 只要插入了任务栈监控代码，便可准确的判断出，在此函数内是否存在任务栈溢出的风险。
// <i> 建议仅在调试阶段开启此项功能，正式的产品应禁用。
#define MCUCFG_TASKSTACKMONITOR         1
///////////////////////////////////////////////////////////////////////////////

                //*** <<< end of configuration section >>> ***//

/******************************************************************************
 *                        Compiler Related Definitions                        *
 ******************************************************************************/

#include MCUCFG_STANDARDHEAD
#if __FPU_PRESENT == __ENABLED__ && __FPU_USED == __ENABLED__
#define MCUCFG_HARDWAREFPU  __ENABLED__
#else
#define MCUCFG_HARDWAREFPU  __DISABLED__
#endif

/******************************************************************************
 *                               OS Definitions                               *
 ******************************************************************************/

/* Header */
#include <string.h>

/* Memory */
#define _SYS_MEM_
#define _CODE_MEM_
#define _STACK_MEM_
#define _CONST_MEM_
#define _TIMINT_MEM_
#define _TIMQRY_MEM_
#define _DEBUG_HMEM_
#define _DEBUG_MMEM_
#define _DEBUG_LMEM_
#define _TASK_MEM_
#define _THDL_MEM_
#define _SV_MEM_
#define _MALLOC_MEM_

/* Register */
#define _SYS_REG_
#define _DEBUG_HREG_
#define _DEBUG_LREG_

/* Typedef */
#ifndef s64
typedef signed long long int s64;
#endif
#ifndef u64
typedef unsigned long long int u64;
#endif
#ifndef bool
typedef u8    bool;
#endif
typedef u8    tBIT;
typedef u32   tSP;
typedef u32   tStackSize;
typedef u32   tDM;
typedef u32   tPC;
typedef u32   tGRP;
typedef u32   tSysTick;

/* Extern */
extern u32 vBASEPRI[2];
extern void *vISS[MCUCFG_ISSDEPTH];
register void **vISP __ASM("r11");
extern u32 * volatile vDM_PSP;
extern volatile u32 vISS_DepthMAX;
extern __ASM u32  __get_HLP(void);
extern __ASM void __isp_push(void *p);
extern __ASM void PendSV_Handler(void);
extern void __entry_monitor(void);

/* * */
#define MCUCFG_MCUARC         __ARM__
#define MCUCFG_MCULEVEL       __ZHENGJINGPAOZI__
#define __USING__
#define __STK_ATTRIBUTE__
#define __PSV_ATTRIBUTE__
#define MCUCFG_DIRMSGTYPE     1
#define __DM_PSP__            vDM_PSP = (u32 *)__get_PSP()
#define __DM_VAR__            tDM r0__, tDM r1__, tDM r2__, tDM r3__
#define __DM_VAL__            0, 0, 0, 0
#define __DM_SIZE__           (&m0 - &m0_ - 1)
#if MCUCFG_HARDWAREFPU == __ENABLED__
#define __CALLER_PUSH_FPU__   (18 * 4) /* {s0-s15,FPSCR,UNKNOW} */
#define __CALLEE_PUSH_FPU__   (16 * 4) /* {s16-s31} */
#else
#define __CALLER_PUSH_FPU__   0
#define __CALLEE_PUSH_FPU__   0
#endif
#define __CALLER_PUSH_REG__   (8 * 4) /* {r0-r3,r12,r14(lr),r15(pc),xPSR} */
#define __CALLEE_PUSH_REG__   (7 * 4) /* {r4-r10} */
#define __CALLER_PUSH__       (__CALLER_PUSH_FPU__ + __CALLER_PUSH_REG__)
#define __CALLEE_PUSH__       (__CALLEE_PUSH_FPU__ + __CALLEE_PUSH_REG__)
#define __BASICSTACKSIZE0__   (__CALLER_PUSH__ + __CALLEE_PUSH__)
#define __BASICSTACKSIZE__    (__BASICSTACKSIZE0__ % 8 ? (__BASICSTACKSIZE0__ / 8 + 1) * 8 : __BASICSTACKSIZE0__)
#define __STACKSIZE_TASKMGR__   (__BASICSTACKSIZE0__ * 2 + (MCUCFG_HARDWAREFPU == __ENABLED__ ? 0 : 24))
#define __STACKSIZE_DEBUGGER__  (__BASICSTACKSIZE0__ * 2)

/* API */
#define mSysTick_InitValue    ((1U * MCUCFG_SYSCLK * SYSCFG_STKCYCLE) / (MCUCFG_STKCLKSOURCE ? 1 : 8))
#define mSysTick_Cycle        mSysTick_InitValue
#define mSysTick_Counter      SysTick->VAL
#define mSTK_Disable          SysTick->CTRL = (MCUCFG_STKCLKSOURCE ? 0x04 : 0x00) | 0x01
#define mSTK_Enable           SysTick->CTRL = (MCUCFG_STKCLKSOURCE ? 0x04 : 0x00) | 0x01 | 0x02
#define mINT_Enable           __enable_irq()
#define mPSV_Trigger          *(u32 *)0xE000ED04 = 0x10000000
#define mTaskNode_Head_       tSP PSP;
#define mTaskNode_Tail_       tSP PSBP;

#define mEnterCritical	\
do{	\
	__set_BASEPRI(vBASEPRI[0]);	\
	OS_NOPxX;	\
}while(vBASEPRI[1] != __get_BASEPRI())

#define mExitCritical	\
do{	\
	__set_BASEPRI(0);	\
	OS_NOPxX;	\
}while(false)

#define mSTK_END __set_BASEPRI(0)
#define mPSV_END __set_BASEPRI(0)

#define mSys_Idle __WFI()

#define mSys_INIT	\
do{	\
	vISP = vISS;	\
	__set_PSP(__get_HLP());	\
	__set_CONTROL(0x02 | (MCUCFG_HARDWAREFPU == __ENABLED__ ? 0x04 : 0x00));	\
	SysTick->LOAD = mSysTick_InitValue;	\
	mSTK_Disable;	\
	/* PendSV_Handler Priority */	\
	*(u8 *)0xE000ED22 = 0xFF;	\
	/* SysTick_Handler Priority */	\
	*(u8 *)0xE000ED23 = 0xFF;	\
	/* 栈8字节对齐 */	\
	*(u32 *)0xE000ED14 |= 0x0200;	\
	/* CP11|CP10 */	\
	MCUCFG_HARDWAREFPU == __ENABLED__ ? *(u32 *)0xE000ED88 |= (0x0F<<20) : OS_NOPx1;	\
	/* ASPEN|LSPEN */	\
	MCUCFG_HARDWAREFPU == __ENABLED__ ? *(u32 *)0xE000EF34 &= 0x3FFFFFFF : OS_NOPx1;	\
	/* vBASEPRI */	\
	do{	\
		u8 i = ~(SCB->AIRCR >> 8) & 7;	\
		while(i--)	\
		{	\
			vBASEPRI[0] *= 2;	\
		}	\
		vBASEPRI[0]--;	\
	}while(false);	\
	__set_BASEPRI(vBASEPRI[0]);	\
	OS_NOPxX;	\
	vBASEPRI[1] = __get_BASEPRI();	\
	__set_BASEPRI(0);	\
	mSTK_Enable;	\
	mINT_Enable;	\
}while(false)

#define mTaskmgr_Counting	\
	counter2 = (counter1 * 100 * (MCUCFG_STKCLKSOURCE ? 1 : 8)) / MCUCFG_SYSCLK / counter2

#define mSTK_Counting	\
do{	\
	if(tick_temp <= mSysTick_Counter) break;	\
	vSTK_Counter1 += tick_temp - mSysTick_Counter;	\
	vSTK_Counter2++;	\
}while(false)

#define mScheduler_INIT	\
	extern volatile u8 vPOPUSH;	\
	extern tspTaskNode vNEWTASK;	\
	static tStackSize stacklen_systick = 0;	\
	if(!stacklen_systick)	\
	{	\
		stacklen_systick = __get_HLP() - __get_PSP();	\
	}	\
	do{}while(false)

#define mTaskStack_INIT	\
do{	\
	node_news->PSBP = (tSP)node_news->BSP + node_news->stacksize;	\
	if(node_news->PSBP % 8)	\
	{	\
		node_news->PSBP /= 8;	\
		node_news->PSBP *= 8;	\
		node_news->stacksize = node_news->PSBP - (tSP)node_news->BSP;	\
	}	\
	node_news->PSP = node_news->PSBP;	\
	*(u32 *)(node_news->PSP - __CALLER_PUSH_FPU__ - 4) = 0x01000000;	\
	*(u32 *)(node_news->PSP - __CALLER_PUSH_FPU__ - 8) = (u32)vACTBUF->entry;	\
	node_news->PSP-= __BASICSTACKSIZE0__;	\
}while(false)

#define mTaskStack_LEN	\
	stacklen = vTASKING->PSBP - __get_PSP() - stacklen_systick + __BASICSTACKSIZE0__

#if MCUCFG_TASKSTACKMONITOR == __ENABLED__
#define mEvery_Monitor	\
do{	\
	if(vTASKING->state == __STOPPED_TSOF__)	\
	{	\
		vFault.overflow_task_stack = true;	\
	}	\
	else if(vTASKING->stacksize < stacklen)	\
	{	\
		vTASKING->state = __STOPPED_TSOF__;	\
		vFault.overflow_task_stack = true;	\
	}	\
}while(false)
#define mEntry_Monitor __entry_monitor()
#else
#define mEvery_Monitor do{}while(false)
#define mEntry_Monitor do{}while(false)
#endif

#define mPUSH_Monitor	\
do{	\
	vPOPUSH = 1;	\
	if(vTASKING->TPL > node_news->TPL)	\
	{	\
		vTASKING->counter = 0;	\
	}	\
}while(false)

#define mUsedTime_END	\
do{	\
	if(usedtime[0])	\
	{	\
		usedtime[0]--;	\
		usedtime[1] += mSysTick_InitValue - counter;	\
	}	\
	else	\
	{	\
		if(usedtime[1] >= counter)	\
		{	\
			usedtime[1] -= counter;	\
		}	\
		else	\
		{	\
			usedtime[1] += mSysTick_InitValue - counter;	\
		}	\
	}	\
	vTASKING->usedtime[0] += usedtime[0];	\
	vTASKING->usedtime[0] += (vTASKING->usedtime[1] + usedtime[1]) / mSysTick_Cycle;	\
	vTASKING->usedtime[1]  = (vTASKING->usedtime[1] + usedtime[1]) % mSysTick_Cycle;	\
}while(false)

#define mUsedTime_INIT	\
do{	\
	usedtime[0] = 0;	\
	usedtime[1] = counter;	\
}while(false)

#define mTaskStack_PUSH	\
do{	\
	if(!vPOPUSH) break;	\
	if(vTaskmgrBinary) mUsedTime_END;	\
}while(false)

#define mTaskStack_POP	\
do{	\
	if(vTaskmgrBinary) mUsedTime_INIT;	\
	vNEWTASK = node_news;	\
	vPOPUSH++;	\
}while(false)

#define mISV_Do(svid)	\
do{	\
	__isp_push(&isv_);	\
	mPSV_Trigger;	\
}while(false)

#define mISV do{}while(false)

#endif
